<?php

/**
 * @author Marc André Audet <root@manhim.net>
 * @copyright Copyright(c) 2009-2010 Marc André Audet
 * @version 1.0.5.23
 * @license http://www.gnu.org/licenses/gpl.txt The GNU General Public License version 3
 *
 *   Manhim's PHP Database Object (PDO wrapper) class, made for Manhim's Object Oriented framework version 2
 *   Version consist of:
 *   [Major Version].[Number of years since 2010].[Month].[Date]
 *   The informations are based on the latest edit of this file, not the whole project.
 *
 *   Copyright (C) 2009-2010 Marc André Audet
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
require_once 'Exceptions.class.php';

/**
 * Manhim's PHP Database Object is a PDO wrapper class.
 * It makes extensive use of the PDO object.
 * @author Marc André Audet
 *
 */
class MPDO
{

	/** @var string $_Username */
    private $_Username;
	/** @var string $_Password */
    private $_Password;
	/** @var string $_DSN */
    private $_DSN;
	/** @var PDO $_PDO */
    private $_PDO;

    /**
     * Supported drivers: mysql, mysql-unixsocket, sqlite, sqlite2, sqlite-memory and sqlite2-memory
     * The parameters changes with different drivers:
     * mysql = Driver, Username, Password, Hostname, Database, Port = 3306
     * mysql-unixsocket = Driver, Username, Password, Socket, Database
     * sqlite/sqlite2 = Driver, Filepath
     * sqlite-memory/sqlite2-memory: Driver
     * @param string $driver
     * @throws MPDOException
     */
    function __construct($driver)
    {
        $args = func_get_args();

        switch ($driver)
        {
            case 'mysql':
                $this->_DSN = $args[0] . ':dbname=' . $args[4] . ';host=' . $args[3] . ';port=' . (isset($args[5]) && $args[5] != 0 ? $args[5] : 3306);
                $this->_Username = $args[1];
                $this->_Password = $args[2];
                break;

            case 'mysql-unixsocket':
                $this->_DSN = $args[0] . ':dbname=' . $args[4] . ';unix_socket=' . $args[3];
                $this->_Username = $args[1];
                $this->_Password = $args[2];
                break;

            case 'sqlite': case 'sqlite2':
                $this->_DSN = $args[0] . ':' . $args[1];
                $this->_Username = null;
                $this->_Password = null;
                break;

            case 'sqlite-memory': case 'sqlite2-memory':
                $this->_DSN = $args[0] . '::memory:';
                $this->_Username = null;
                $this->_Password = null;
                break;

            default:
                throw new MPDOException('Unsupported PDO driver name.');
        }
    }

	/**
     * Cleanup the PDO class underneath.
     */
    function __destruct()
    {
        $this->_PDO = null;
    }

	/**
     * Initiate the connection to the database.
     * @return boolean
     * @throws MDPOException
     */
    function Connect()
    {
        try
        {
            $this->_PDO = new PDO($this->_DSN, $this->_Username, $this->_Password);
        }
        catch (PDOException $e)
        {
            throw new MPDOException($e->getMessage(), $e->getCode());
        }

        return true;
    }

	/**
     * Build a query and return a MPDOQuery.
     * @param string $query
	 * @param boolean $execute
     * @return MPDOQuery
     */
    function Query($query, $execute = false)
    {
        $u_args = null;

        if (func_num_args() > 2)
        {
            $args = func_get_args();

            if (!is_array($args[2]))
            {
                $c_args = count($args);
                $u_args = array();
                for ($i = 2; $i < $c_args; $i++)
                {
                    $u_args[] = $args[$i];
                }
            }
            else
            {
                $u_args = $args[2];
            }
        }
        else
        {
            $u_args = null;
        }

        $q = new MPDOQuery($this->_PDO->prepare($query));
        if ($execute) $q->Execute($u_args);

        return $q;
    }

	/**
     * Return the last inserted ID.
     * @return var
     */
    function GetLastInsertId()
    {
        return $this->_PDO->lastInsertId();
    }

}

/**
 * The statement of a MPDO Query.
 * @author Marc André Audet
 *
 */
class MPDOQuery
{

	/** @var PDOStatement $_Statement */
    private $_Statement;

	/**
     * Receive a PDOStatement and filter the result.
     * @param PSOStatement $statement
     * @throws MPDOQueryException
     */
    function __construct(&$statement)
    {
        if (is_object($statement) && get_class($statement) == 'PDOStatement') $this->_Statement = &$statement;
        else if (is_object($statement) && get_class($statement) == 'PDOException') throw new MPDOQueryException($statement->getMessage(), $statement->getCode());
        else throw new MPDOQueryException('Invalid PDOStatement');
    }

	/**
     * Execute the prepared query.
     * @param array $args
     * @return boolean
     * @throws MPDOQueryException
     */
    function Execute($args)
    {
        if (!$this->_Statement->execute($args))
        {
            $err = $this->_Statement->errorInfo();
            throw new MPDOQueryException('Failed to execute the query: ' . $err[2]);
            return false;
        }

        return true;
    }

	/**
     * Fetch a single row and place the pointer at the start of the next row.
     * @return array
     */
    function Fetch()
    {
        return $this->_Statement->fetch(PDO::FETCH_BOTH);
    }

	/**
     * Fetch a single row and place the pointer at the start of the next row. Returns an associative array.
     * @return array
     */
    function FetchAssoc()
    {
        return $this->_Statement->fetch(PDO::FETCH_ASSOC);
    }

	/**
     * Fetch every rows.
     * @return array
     */
    function FetchAll()
    {
        return $this->_Statement->fetchAll(PDO::FETCH_BOTH);
    }

	/**
     * Fetch every rows. Returns an associative array.
     * @return array
     */
    function FetchAllAssoc()
    {
        return $this->_Statement->fetchAll(PDO::FETCH_ASSOC);
    }

}

/**
 * MPDO object exception.
 * General purpose exception.
 * @author Marc André Audet
 *
 */
class MPDOException extends CustomException
{

}

/**
 * MPDOQuery object exception.
 * General purpose exception.
 * @author Marc André Audet
 *
 */
class MPDOQueryException extends CustomException
{

}

?>